/*
 * The gTree filesystem
 *
 * Copyright (c) 2017 ARM Limited
 *
 * Licensed under the Apache License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef GFS_H_
#define GFS_H_
//=======================功能定义====================================================
#define GFS_MEDIAN_SCAN		//中位法检索文件名(提升打开文件速度)
#define GFS_RECORD_FUNTION	//流水记录功能

//===============基本配置定义===========================================
#define GFS_BLOCK_SIZE 		FLASH_SECTOR_SIZE
#define GFS_PAGE_SIZE		FLASH_PAGE_SIZE
//-------定义文件系统引导区(自动计算)----------------------------
#define GFS_BIT_FLAG 		((GFS_FILE_SIZE-GFS_FILE_HDNM+31)/32)
#define GFS_FILE_MIN		100	//文件最少数量
#define GFS_HEAD_MIN		(GFS_BIT_FLAG*8 + GFS_FILE_MIN*2 + 10)
#if(GFS_HEAD_MIN > 512)
#define GFS_BIT_HEAD 		(1024)
#elif(GFS_HEAD_MIN > 256)
#define GFS_BIT_HEAD 		(512)
#else
#define GFS_BIT_HEAD 		(256)
#endif
#define GFS_FILE_MAX 		((GFS_BIT_HEAD - (GFS_BIT_FLAG*8 + 6 + 4))/2)
#define GFS_FLAG_Z 			((GFS_FILE_MAX & 0xff) ^ (GFS_BIT_HEAD/GFS_PAGE_SIZE))

//------------定义文件体(单个文件最大8M)-----------------------------------
//#define GTREE_FS_NAME_MAX		(96)
//#define GTREE_FS_UNIT_SIZE	4096
//-------------定义文件体(单个文件最大4M,4M flash必选)----------------------
#define GTREE_FS_NAME_MAX	(32)
#define GTREE_FS_UNIT_SIZE	2048

#if(GTREE_FS_UNIT_SIZE > GFS_BLOCK_SIZE)
#error "##GTREE_S_SUNIT_SIZE is too large"
#endif


//=======================标记定义====================================================
#define GFS_BASIC_NULL		0xFFFF	//无数
#define GFS_BASIC_GUID		0xEEEE	//引导
#define GFS_BASIC_DATA		0xDDDD	//数据
#define GFS_BASIC_BAD		0x4884	//坏块

#define GFS_INDEX_NULL 		GFS_BASIC_NULL

#define REV_ENCOD(var)		(~(var))        //Reverse encoding
#define INDEX_COUNT_DOWN 	//定义空间地址负向增长，减少空间擦除

#ifdef INDEX_COUNT_DOWN
#define	InversBlock(iv)		(iv)	 //flash入口都定为反码,加一个固定值避免 ~0 == 0xFFFF
#define	SetInversBlock(iv)		 //flash入口都定为反码,加一个固定值避免 ~0 == 0xFFFF
#else
#define	InversBlock(iv)		(~((iv)+1))	 //flash入口都定为反码,加一个固定值避免 ~0 == 0xFFFF
#define	SetInversBlock(iv)	(iv = InversBlock(iv))	 //flash入口都定为反码,加一个固定值避免 ~0 == 0xFFFF
#endif

// File types 文件夹标记	[f]文件夹,[e]可执行文件，[s]字符串文件，[b]二进制文件
enum fType {
    GFS_TYPE_FLD	= 'f',	//Folder
    GFS_TYPE_BIN	= 'b',
	GFS_TYPE_STR	= 's',
	GFS_ENC_STR		= 'd',	//加密钥文件
	GFS_TYPE_EXE	= 'e',	//可执行文件
	GFS_TYPE_COT	= 'i',	//计数单元
};

typedef struct
{
	u16	head;	//块头:[FFFF] 已经察除，[48||84] 坏块，[EEEE] 引导数据，[DDDD] 使用数据
	u16	index;	//平衡记录器 -> 文件
	u8	flagZ;			// (GFS_BIT_HEAD/GFS_PAGE_SIZE)^(GFS_FILE_MAX&0xff) 头本身校验
	u8	flagClear;		//已经察除,[FF]未察除，55 已经察除
}DfGTreeFsBlockHead;

typedef struct
{
	DfGTreeFsBlockHead t;
	u16		BlockMax, PreMax; // 4 byte
	u16		BlockIndex[GFS_FILE_MAX];	//一级入口，直接对应文件或文件夹	
	//-------GFS_BIT_FLAG*8 byte-----------
	u32		NullBit[GFS_BIT_FLAG];	//空块 block
	u32		EraseBit[GFS_BIT_FLAG];	//需要察除的块
}DfGTreeFsGlobal;

typedef struct
{
	u16 gfsCoutStart;	//文件引导区地址，平衡记数器
	u16 gfsCoutSize;	//文件引导区空间大小
	u16 gfsCoutIndex;	//文件引导区平衡记数器
	u16 gfsBlockStart;	//文件内容起始地址
	u16 gfsBlockSize;	//文件内容空间大小
	u16 gfsNewIndex;	//文件空间平衡记数器
	DfGTreeFsGlobal g;	//文件引导区内容，存于平衡记数器中
}DfGTreeFsBasi;


typedef struct
{
	char	filepath[GTREE_FS_NAME_MAX];	//文件夹名或文件名
	char	check[3];	//加密文件校验值
	char	fType;		//fType文件夹标记	[f]文件夹,[e]可执行文件，[s]字符串文件，[b]二进制文件
	u32		InvLen;		//返数长度，文件递增中减少FLASH 察除。取长(~InvLen)
}DfGTreeFsFileName;

//----------定义文件系统数据--DATA-----------
typedef struct	//	GTREE_FS_UNIT_SIZE
{
	DfGTreeFsFileName name;
	u16 	fdIndex[(GTREE_FS_UNIT_SIZE-GTREE_FS_NAME_MAX-8)/2]; //文件内容块索引
}DfgFsUnitHead;

typedef struct	//	GFS_BLOCK_SIZE
{
	DfgFsUnitHead h;  //	GTREE_FS_UNIT_SIZE
	#if(GFS_BLOCK_SIZE > GTREE_FS_UNIT_SIZE)
	u8	fData[GFS_BLOCK_SIZE - GTREE_FS_UNIT_SIZE];	//文件内容，最大2048
	#endif
}DfgFsUnitBlock;

#define 	GFS_PATH_TAG				('/')
//========文件路径检查===返回 1,文件路径，-1非文件夹，字符不匹配，0 匹配字符------
extern int gfs_strcmp_path(u8* pPath,u8* strTag,u8 pathTag);
extern void memcpy_u32(u32* pU1,u32* pU2,int len);
extern void memset_u32(u32* pU1,u32 tag,int len);
extern int memcmp_u32(u32* pU1,u32* pU2,int len);

extern int Incekxor(u8* destin,u8* source,int len);

extern void gfs_balanced_global_save(int pNew);

extern int gfs_FsReadblock(u16 block,u16 offset,void* buff,u16 size);
extern int gfs_FsWriteblock(u16 block,u16 offset,void* buff,u16 size);
extern int gfs_FsEraseblock(u16 block);

extern u16 gfs_get_block_index(u16 i);

extern u16 gfs_get_new_guide(void);
extern void gfs_free_index_guide(u16 iGuide,u16 iEntry);
#ifdef GFS_MEDIAN_SCAN
extern u16 gfs_median_block_loadnew(u16 *pIndexGuide,u16 oldIndex,u16 newIndex,char *pFilepath);
#else
extern int Gfs_LoadIndexGuide(u16 IndexGuide,u16 IndexEntry);
#endif

extern int gfs_record_erase(u16 IndexArray);
extern void gfs_unrecord_erase(u16 IndexArray);
extern void gfs_record_delete(u16* pIndexArray,int max);

extern int gfs_check_erase_block_bit(int force);
extern u16 gfs_get_next_nullblock(void);
extern void gfs_ClearFile(u16 IndexGuide,u16 IndexEntry,u16* pGIndex,int gLen);

#ifdef GFS_RECORD_FUNTION
typedef struct
{
	u16	head;	//块头:[FFFF] 已经察除，[48||84] 坏块，[EEEE] 引导数据，[DDDD] 使用数据
	u16	Index;	//块索引
	int count;
}DfgHeadCheck;
typedef struct	//固定 sizeof(DfgHeadCheck) + block/2
{
	DfgHeadCheck	hg;
	u8				dg[GFS_BLOCK_SIZE - GTREE_FS_UNIT_SIZE - 8];	//文件内容，固定 block/2
}DfgRcUnitData;

typedef struct
{
	char	filepath[GTREE_FS_NAME_MAX];	//文件夹名或文件名
	u16 	blockNum;		//flash 总块数
	u16 	parLen;			//参数长度	= aSize
	u16 	pgSize;			//页数长度	= 256 *((aSize+255)/256)
	char	check,fType;	//fType文件夹标记	[c]计数文件
	
	u16 	PageNum;		//单页数量  	= 4096/pgSize
	u16 	PageMax;		//最大单页	= PageNum * block
}DfGRcUnitName;	// size == DfGTreeFsFileName->size

typedef struct	//fdIndex 地位置与 DfgFsUnitHead.fdIndex 地位对应 ，固定 block/2 - sizeof(DfgHeadCheck) 
{
	DfGRcUnitName name;
	u16 	fdIndex[(GTREE_FS_UNIT_SIZE - GTREE_FS_NAME_MAX - 18) / 2]; //文件内容块索引
	u16 	PageIndex;		//文件引导区平衡记数器，,外部初始化。
	int 	count;			//计数器,外部初始化，对应该 DfgHeadCheck -> count
}DfgRcUnitHead;

typedef struct
{
	DfgRcUnitHead h;
	DfgRcUnitData d;
}DfgRcUnitBlock;

extern int gfs_RecordSpaceInit(DfgRcUnitHead *pHead,int num,int aSize);
extern int gfs_RecordNewSearch(DfgRcUnitHead *pHead);
extern int gfs_RecordRead(DfgRcUnitBlock *pUnit,int PreIndex,void* pBuff);
extern int gfs_RecordSave(DfgRcUnitBlock *pUnit,void* pBuff);
#endif

extern int gfs_Init(u16 startCap,u16 fdSize,u16 countSize,int brFlag);
extern int gfs_Fomat(char *pKey);


extern int gfs_checkALL(void);

//================================================================
enum gfs_UP_FLAG {
	G_UP_NULL	= 0x00, //空标记不需要任何操作
    G_UP_G_NEW	= 0x80, //更新引导区，新块更新 
	G_UP_G_OLD  = 0x40, //更新引导区，旧块更新
	G_UP_H_NEW  = 0x20, //更新文件头，新块更新 
	G_UP_H_OLD  = 0x10, //更新文件头，旧块更新
	G_UP_E_ARB  = 0x08, //擦除标记
	G_UP_L_ARB  = 0x04, //更新长度标记
};
//----------------------------------------------------------

typedef union
{
	DfGTreeFsFileName	f;
#ifdef GFS_RECORD_FUNTION
	DfGRcUnitName		a;
#endif
}gFsNameUnit;

typedef struct _tFILE
{
	u32		fLen;	//文件当前返码长度，取长(~fInvLen)
	u32		fOffset;	//文件当前偏移
	u16 	IndexGuide;	//索引块入口
	u16 	IndexEntry;	//文件入口
	
	u16 	IndexB; 	//块索引
	u16 	bOffet; 	//块偏移 

	u16 	fOpenFlag;
	u8		flagUp;		//更新标记 对应：gfs_UP_FLAG
	u8		flagNew;	//重新写入内容
	//----------Block 存放内容集-[GFS_BLOCK_SIZE]-----------
	union
	{
		DfgFsUnitBlock u;
#ifdef GFS_RECORD_FUNTION
		DfgRcUnitBlock a;
#endif
	};
}tFILE,*gFILE;	//文件句柄

extern int gfs_SetOffset(gFILE pfd,int offset, int whence);
extern int gfs_ExportAllpath(char *pOutName[],int MaxNum,char *pbuff);

extern u16 gfs_ScanFileName(gFsNameUnit *pName, const char *path); //,char pathType

#endif
